/**
 * Copyright (C) 2025 pony working team
 * SPDX-License-Identifier: MulanPSL-2.0
 */

/* define to prevent recursive inclusion -------------------------------------*/
#ifndef __X_RING_H__
#define __X_RING_H__

/* includes (standard library, system) ---------------------------------------*/
#include <stddef.h>
#include <stdbool.h>
/* includes (other library) --------------------------------------------------*/
/* includes (project) --------------------------------------------------------*/
/* includes (local) ----------------------------------------------------------*/

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/* defines -------------------------------------------------------------------*/
/* typedefs ------------------------------------------------------------------*/

/**
 *      tail      head
 *      +---------+---------+
 * buf  |/////////|         |
 *      +---------+---------+
 *      \                   /
 *       `--------------- size
 *
 * empty: tail == head
 * full : tail == (head + 1) % size
 *        or
 *        head - tail == size
 */
typedef struct ring {
    size_t head;        /* write pos */
    size_t tail;        /* read pos */
    size_t size;        /* buf size, must be power of 2 */
    unsigned char *buf; /* pointer to buffer array */
} ring_t;

/* macro ---------------------------------------------------------------------*/
/* inlines -------------------------------------------------------------------*/

/**
 * ring_reset - empty the ring buffer
 * @ring: the ring buf.
 */
static inline void ring_reset(ring_t *ring)
{
    ring->head = 0;
    ring->tail = 0;
}

/**
 * ring_len - get the number of bytes in the ring buffer
 * @ring: the ring buf.
 */
static inline size_t ring_len(ring_t *ring)
{
    return ring->head - ring->tail;
}

/**
 * ring_empty - check if the ring is empty
 * @ring: the ring buf.
 */
static inline bool ring_empty(ring_t *ring)
{
    return ring->tail == ring->head;
}

/**
 * ring_full - check if the ring is full
 * @ring: the ring buf.
 */
static inline bool ring_full(ring_t *ring)
{
    return ring_len(ring) == ring->size;
}

/**
 * ring_peek - just return value from buf [tail ~ head] by index, data will not
 *             out of ring
 * @ring: the ring buf.
 * @idx:  the index from head to read.
 */
static inline unsigned char ring_peek(ring_t *ring, size_t idx)
{
    return ring->buf[(ring->tail + idx) & (ring->size - 1)];
}

/* externs -------------------------------------------------------------------*/

extern int ring_init(ring_t *ring, unsigned char *buf, size_t size);
extern ring_t *ring_create(size_t size);
extern void ring_destroy(ring_t *ring);
extern size_t ring_put(ring_t *ring, unsigned char *buf, size_t len);
extern size_t ring_put_force(ring_t *ring, unsigned char *buf, size_t len);
extern size_t ring_putc(ring_t *ring, unsigned char byte);
extern size_t ring_putc_force(ring_t *ring, unsigned char byte);
extern size_t ring_get(ring_t *ring, unsigned char *buf, size_t len);
extern size_t ring_getc(ring_t *ring, unsigned char *byte);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* __X_RING_H__ */
